﻿#include "Logger.h"
#include "utils/Time/Time.h"

#include <QCoreApplication>
#include <cstdio>
#include <exception>

#if defined(Q_OS_WIN)
#include <windows.h>
#else
#include <csignal>
#endif

Logger &Logger::instance()
{
    static Logger inst;
    return inst;
}

Logger::Logger() {}
Logger::~Logger()
{
    if (m_logFile.isOpen()) {
        m_stream.flush();
        m_logFile.close();
    }
}

bool Logger::init(const QString &filePath, bool alsoConsoleOutput)
{
    static bool inited = false;
    if (inited) return true;

    m_consoleOutput = alsoConsoleOutput;

    m_logFile.setFileName(filePath);
    if (!m_logFile.open(QIODevice::Append | QIODevice::Text)) {
        qWarning() << QObject::tr("Cannot open log file: %1").arg(filePath);
        return false;
    }
    m_stream.setDevice(&m_logFile);
    m_stream.setCodec("UTF-8");

    // 安装 Qt 消息处理器
    qInstallMessageHandler(Logger::messageHandler);

    // 安装崩溃和异常处理
    setupCrashHandler();

    inited = true;
    return true;
}

void Logger::messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    Q_UNUSED(context);

    Logger &logger = Logger::instance();

    QString typeStr;
    switch (type) {
    case QtDebugMsg:    typeStr = "   <Debug>"; break;
    case QtInfoMsg:     typeStr = "    <Info>"; break;
    case QtWarningMsg:  typeStr = " <Warning>"; break;
    case QtCriticalMsg: typeStr = "<Critical>"; break;
    case QtFatalMsg:    typeStr = "   <Fatal>"; break;
    default:            typeStr = " <Unknown>"; break;
    }

    QString time = Time::getTimeString();
    QString logText = QString("[%1] %2: %3").arg(time, typeStr, msg);

    {
        QMutexLocker locker(&logger.m_mutex);
        if (logger.m_stream.device()) {
            logger.m_stream << logText << "\n\n";
            logger.m_stream.flush();
        }
    }

    if (logger.m_consoleOutput) {
        fprintf(stderr, "%s\n", logText.toLocal8Bit().constData());
        fflush(stderr);
    }

    if (type == QtFatalMsg) {
        abort();
    }
}

void Logger::log(QtMsgType type, const QString &msg)
{
    messageHandler(type, QMessageLogContext(), msg);
}

void Logger::setupCrashHandler()
{
    // C++ 未捕获异常
    std::set_terminate([]() {
        try {
            std::rethrow_exception(std::current_exception());
        } catch (const std::exception &e) {
            Logger::instance().log(QtCriticalMsg,
                                   QObject::tr("Exception: %1").arg(e.what()));
        } catch (...) {
            Logger::instance().log(QtCriticalMsg, QObject::tr("Unknown Exception"));
        }
        abort();
    });

#if defined(Q_OS_WIN)
    SetUnhandledExceptionFilter(windowsExceptionHandler);
#else
    signal(SIGSEGV, unixSignalHandler);
    signal(SIGABRT, unixSignalHandler);
    signal(SIGFPE,  unixSignalHandler);
    signal(SIGILL,  unixSignalHandler);
#endif
}

#if defined(Q_OS_WIN)
LONG WINAPI Logger::windowsExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
    Logger::instance().log(QtCriticalMsg,
                           QObject::tr("Windows Exception: code=0x%1")
                               .arg(ExceptionInfo->ExceptionRecord->ExceptionCode, 0, 16));
    return EXCEPTION_EXECUTE_HANDLER; // 写日志后退出
}
#else
void Logger::unixSignalHandler(int sig)
{
    Logger::instance().log(QtCriticalMsg,
                           QObject::tr("Unix Signal Error: sig=%1").arg(sig));
    // 写完日志后立即终止
    signal(sig, SIG_DFL);
    raise(sig);
}
#endif
